/**
 * 创建一个防抖函数，该函数会在最后一次调用后的指定时间后执行，
 * 或者立即执行并在后续调用中等待指定时间后执行。
 *
 * @param fn - 要进行防抖处理的原函数。
 * @param wait - 在函数停止调用后等待的时间（毫秒）。
 * @param immediate - 是否立即执行函数，默认为false。
 * @returns 返回防抖处理后的函数。
 */
function debounce<T extends (...args: any[]) => any>(
  fn: T,
  wait: number,
  immediate: boolean = false
): (...args: Parameters<T>) => any {
  let timer: NodeJS.Timeout | null = null
  let context: ThisParameterType<T> | null = null
  let args: Parameters<T> | null = null
  return function (this: any, ..._args: Parameters<T>): any {
    context = this
    args = _args
    timer && clearTimeout(timer)

    if (immediate) {
      // 立即执行，延时内不执行，延迟过后之后再执行
      const isCallNow = !timer
      timer = setTimeout(function () {
        fn.apply(context, args!)
        timer = null
      }, wait)
      if (isCallNow) {
        fn.apply(context, args!)
      }
    } else {
      timer = setTimeout(() => {
        fn.apply(context, args!)
      }, wait)
    }
  }
}

export default debounce
